package org.scboy.common.service.imp;

import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

import org.apache.dubbo.config.annotation.DubboReference;
import org.scboy.common.annotation.Menu;
import org.scboy.common.annotation.Permission;
import org.scboy.common.service.LoggerService;
import org.scboy.logger.api.ILoggerManager;
import org.scboy.utils.entitys.common.RequestEntity;
import org.scboy.utils.entitys.rbac.LoginUser;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;

import cn.hutool.core.util.StrUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import jakarta.servlet.http.HttpServletRequest;

@Configuration
@EnableAsync
public class LoggerServiceImpl implements LoggerService {

	@DubboReference(check=false)
	ILoggerManager manager;
	
	Log log=LogFactory.get();
	
	@Value("${spring.application.name}")
	String appName;
	
	@Async
	public void writeRequestLog(ContentCachingRequestWrapper request,ContentCachingResponseWrapper response,HandlerMethod method) {
		
		//如果没有启动日志服务，直接跳过日志记录。
		if(manager==null) {
			return;
		}
		
        RequestEntity entity=new RequestEntity();
        
		//请求链路ID
		String requestId = request.getHeader("Bmps-Request-Id");
		Permission permission= method.getMethodAnnotation(Permission.class);
		
		Menu menu= method.getBean().getClass().getAnnotation(Menu.class);
		
        entity.setAppName(appName);
        String permissionName="";
        if(menu!=null) {
        	permissionName+=menu.value()+".";
        }
		if(permission!=null) {
			permissionName+=permission.value();
		}
		
		entity.setName(permissionName);
		
		//获取登录对象
		LoginUser loginUser= (LoginUser)request.getAttribute("LOGIN_USER");
		
        entity.setRequestId(requestId);
		entity.setToken(loginUser.getToken());;
		entity.setUserId(loginUser.getUserInfo().getId());;
		entity.setUserName(loginUser.getUserInfo().getUserName());;
		entity.setOrgId(loginUser.getUserInfo().getOrg().getId());
		
        /**
         * 请求服务的地址
         */
		entity.setUrl(request.getRequestURL().toString());
		entity.setUri(request.getRequestURI());
		
		
		//读取方法
		entity.setMethod(request.getMethod());
		
		String requestBody=StrUtil.str(request.getContentAsByteArray(),Charset.forName("UTF-8"));
		
		entity.setRequestBody(StrUtil.isNotEmpty(requestBody)?requestBody:"{}");
		
		//非JSON返回值，不输入日志。
		if("application/json".equals(response.getContentType())) {
			String responseBody=StrUtil.str(response.getContentAsByteArray(),Charset.forName("UTF-8"));
			entity.setResponseBody(StrUtil.isNotEmpty(responseBody)?responseBody:"{}");
		}else {
			entity.setResponseBody("{}");
		}
		
		Map<String, String> headers=new HashMap<String, String>();
		Enumeration<String> enumeration = request.getHeaderNames();
		while (enumeration.hasMoreElements()) {
			String name = enumeration.nextElement();
			String value = request.getHeader(name);
			headers.put(name, value);
		}
		entity.setHeadData(headers);
		
		Map<String, String> params=new HashMap<String, String>();
		
		Enumeration<String> paramNames = request.getParameterNames();

		while(paramNames.hasMoreElements()) {
           String name = (String)paramNames.nextElement();
           String value = request.getParameter(name);
           params.put(name, value);
       	}
		entity.setParams(params);
		
		manager.writeRequestLog(entity);
	}
	
	public String getPostData(HttpServletRequest request) {
        StringBuilder data = new StringBuilder();
        String line;
        BufferedReader reader;
        try {
            reader = request.getReader();
            while (null != (line = reader.readLine())) {
                data.append(line);
            }
        } catch (IOException e) {
            return null;
        }
        return data.toString();
    }
}
